#ifndef MATRIX_H
#define MATRIX_H

#include "vector.h"
#include "point.h"
#include "glframe.h"

class Matrix
{
public:
    Matrix();
    Matrix(const Matrix &m);
    Matrix(const Vector &col1, const Vector &col2, const Vector &col3, const Vector &col4);
    Matrix(const Vector &col1, const Vector &col2, const Vector &col3);
    virtual ~Matrix();

    static const Matrix identity();
    static const Matrix xRotationMatrix(double angle);
    static const Matrix yRotationMatrix(double angle);
    static const Matrix zRotationMatrix(double angle);
    static const Matrix rotationMatrix(double angle, const Vector& axis);
    static const Matrix rotationMatrix(double angle, double x, double y, double z);
    static const Matrix translationMatrix(const Vector &t);
    static const Matrix translationMatrix(double x, double y, double z);
    static const Matrix scalingMatrix(double sx, double sy, double sz);
    static const Matrix coordChangeMatrix(const GlFrame &dst);

    Matrix& operator=(const Matrix &b);
    void assignRow(int row, const Vector &v);
    void assignRow(int row, const Point &p);
    void assignCol(int col, const Vector &v);
    void assignCol(int col, const Point &p);
    Vector row(int row) const;
    Vector col(int col) const;
    Matrix transpose() const;
    void toOpenGLMatrix(double *glMatrixBuffer) const;
    inline double& operator()(int row, int col) {
      return elements_[row][col];
    };

    inline double operator()(int row, int col) const {
      return elements_[row][col];
    };

private:
    double elements_[4][4];
    void copy(const Matrix &b);
};

Matrix operator+(const Matrix &left, const Matrix &right);
Matrix operator-(const Matrix &left, const Matrix &right);
Matrix operator*(const Matrix &left, const Matrix &right);
Vector operator*(const Matrix &M, const Vector &b);
Point operator*(const Matrix &M, const Point &p);

#endif // MATRIX_H
